using System;
using OhioState.Graphics;
using Tao.OpenGl;

namespace OhioState.Graphics.OpenGL
{
    public abstract class TextureGL : ITexture, IOpenGLResource, IDisposable
    {
        protected int _width;
        public int Width
        {
            get { return _width; }
        }
        protected int _height;
        public int Height
        {
            get { return _height; }
        }
        protected int _depth;
        public int Depth
        {
            get { return _depth; }
        }
        protected TexelFormat _type;
        public TexelFormat TexelType
        {
            get { return _type; }
        }
        protected uint _texID = 0;

       
        protected int _texGLType = Gl.GL_TEXTURE_1D;
        public virtual void bind()
        {
            if (!_created)
            {
                createTexture();
            }
            Gl.glBindTexture(_texGLType, _texID);
            Gl.glEnable(_texGLType);
            if( _applyParameters)
            {
                applyParameters();
                _applyParameters = false;
            }         
        }
        public virtual void unbind()
        {
            Gl.glDisable(_texGLType);
        }

        protected bool _created = false;
        protected abstract void createTexture();
        protected bool _applyParameters = true;
        protected virtual void applyParameters()
        {
            Gl.glTexParameteri(_texGLType, Gl.GL_TEXTURE_WRAP_S, Gl.GL_CLAMP_TO_EDGE);
            Gl.glTexParameteri(_texGLType, Gl.GL_TEXTURE_WRAP_T, Gl.GL_CLAMP_TO_EDGE);
            Gl.glTexParameteri(_texGLType, Gl.GL_TEXTURE_WRAP_R, Gl.GL_CLAMP_TO_EDGE);
            Gl.glTexParameteri(_texGLType, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR);
            Gl.glTexParameteri(_texGLType, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR);
            Gl.glTexEnvf(Gl.GL_TEXTURE_ENV, Gl.GL_TEXTURE_ENV_MODE, Gl.GL_MODULATE);
       }
        protected TextureGL()
        {

        }

        #region IOpenGLResource Members
        public uint GUID
        {
            get {
                if (!_created)
                {
                    createTexture();
                }
                return _texID;
            }
        }
        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            Dispose(true);
        }
        private void Dispose(bool disposing)
        {
            if (_created)
            {
                Gl.glDeleteTextures(1, ref _texID);
            }
                        
            GC.SuppressFinalize(this);
        }

        #endregion

    }


    public class Texture1DGL : TextureGL
    {
        public Texture1DGL(int width, TexelFormat type)
        {
             _texGLType = Gl.GL_TEXTURE_1D;
             _width = width;
             _height = 1;
             _depth = 1;
             _type = type;
         }
        protected override void createTexture()
        {
            Gl.glGenTextures(1, out _texID);
            //Gl.glActiveTexture(Gl.GL_TEXTURE0);
            Gl.glBindTexture(Gl.GL_TEXTURE_1D, _texID);
            int format = OhioState.Graphics.OpenGL.OpenGLAdapter.ConvertFormat(this.TexelType.Format);
            int type = OhioState.Graphics.OpenGL.OpenGLAdapter.ConvertType(this.TexelType.Type);
            IntPtr junk = (IntPtr)0;
            Gl.glTexImage1D(Gl.GL_TEXTURE_1D, 0, format, this.Width, 0, format, type, junk);
            _created = true;
        }
    }


    public class Texture2DGL : TextureGL
    {
        public Texture2DGL(int width, int height, TexelFormat type)
        {
             _texGLType = Gl.GL_TEXTURE_2D;
             _width = width;
             _height = height;
             _depth = 1;
             _type = type;
         }
        //public Texture2DGL(TextureProxy texProxy)
        //{
        //    _texGLType = Gl.GL_TEXTURE_2D;
        //    _width = texProxy.Width;
        //    _height = texProxy.Height;
        //    _depth = 1;
        //    _type = texProxy.Type;
        //}
       protected override void createTexture()
        {
            Gl.glDisable(Gl.GL_TEXTURE_2D);
            Gl.glGenTextures(1, out _texID);
            //Gl.glActiveTexture(Gl.GL_TEXTURE0);
            Gl.glBindTexture(_texGLType, _texID);
            int format = OhioState.Graphics.OpenGL.OpenGLAdapter.ConvertFormat(this.TexelType.Format);
            int type = OhioState.Graphics.OpenGL.OpenGLAdapter.ConvertType(this.TexelType.Type);
            IntPtr junk = (IntPtr)0;
            if (format == Gl.GL_RGBA16)//added for pre-integrated TF support
            {
                Gl.glTexImage2D(_texGLType, 0, Gl.GL_RGBA16, this.Width, this.Height, 0, Gl.GL_RGBA, Gl.GL_UNSIGNED_SHORT, junk);
            }
            else
            {
                Gl.glTexImage2D(_texGLType, 0, format, this.Width, this.Height, 0, format, type, junk);
            }
            //int error = Gl.glGetError();
            // if (error > 0)
            //    Console.WriteLine();
            _created = true;
        }
        
    }


    public class Texture3DGL : TextureGL
    {
        public Texture3DGL(int width, int height, int depth, TexelFormat type)
        {
             _texGLType = Gl.GL_TEXTURE_3D;
             _width = width;
             _height = height;
             _depth = depth;
             _type = type;
        }
        protected override void createTexture()
        {
            Gl.glGenTextures(1, out _texID);
            //Gl.glActiveTexture(Gl.GL_TEXTURE0);
            Gl.glBindTexture(_texGLType, _texID);
            int format = OhioState.Graphics.OpenGL.OpenGLAdapter.ConvertFormat(this.TexelType.Format);
            int type = OhioState.Graphics.OpenGL.OpenGLAdapter.ConvertType(this.TexelType.Type);
            IntPtr junk = (IntPtr)0;
            Gl.glTexImage3D(_texGLType, 0, format, this.Width, this.Height, this.Depth, 0, format, type, junk);
            _created = true;
        }
    }
}
